package com.ruoyi.business.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ruoyi.bizsys.domain.ExtMonnifyReservedAccounts;
import com.ruoyi.bizsys.domain.ExtReqLog;
import com.ruoyi.bizsys.domain.RepaymentOrder;
import com.ruoyi.bizsys.service.IExtMonnifyReservedAccountsService;
import com.ruoyi.bizsys.service.IExtReqLogService;
import com.ruoyi.bizsys.service.IRepaymentOrderService;
import com.ruoyi.business.service.ICallbackService;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.text.ParseException;
import java.util.*;

/**
 * @Author: Jamnsin
 * @Date: 2021/1/13 5:08 下午
 */
@Slf4j
@RestController
@RequestMapping("/callback")
public class CallbackController {

    @Autowired
    ICallbackService callbackService;

    @Autowired
    IExtReqLogService extReqLogService;

    @Autowired
    IExtMonnifyReservedAccountsService monnifyReservedAccountsService;

    @Autowired
    IRepaymentOrderService repaymentOrderService;

    @PostMapping("/webhook")
    @Log(title = "Paystack 回调事件", businessType = BusinessType.CALLBACK)
    public AjaxResult callbackEvent(@RequestBody String res) throws ParseException {
        callbackService.dealEvent(JSON.parseObject(res));
        return AjaxResult.success();
    }

    @PostMapping("/webhook/monnify")
    @Log(title = "Monnify 回调事件", businessType = BusinessType.CALLBACK)
    public AjaxResult webHookMonnify(@RequestBody String res) {

        String custNo = "";

        if (JSON.parseObject(res) != null && JSON.parseObject(res).getJSONObject("product") != null && JSON.parseObject(res).getJSONObject("product").getString("type") != null) {
            if ("WEB_SDK".equals(JSON.parseObject(res).getJSONObject("product").getString("type"))) {
                //card
                RepaymentOrder repaymentOrder = new RepaymentOrder();
                repaymentOrder.setRepaymentNo(JSON.parseObject(res).getString("paymentReference"));
                List<RepaymentOrder> repaymentOrders = repaymentOrderService.selectRepaymentOrderList(repaymentOrder);
                custNo = repaymentOrders.get(0).getCustNo();
            }
            if ("RESERVED_ACCOUNT".equals(JSON.parseObject(res).getJSONObject("product").getString("type"))) {
                //TTS
                custNo = getCustNoByAccountReference(res);
            } else {
                RepaymentOrder repaymentOrder = new RepaymentOrder();
                repaymentOrder.setRepaymentNo(JSON.parseObject(res).getString("paymentReference"));
                List<RepaymentOrder> repaymentOrders = repaymentOrderService.selectRepaymentOrderList(repaymentOrder);
                custNo = repaymentOrders.get(0).getCustNo();
            }
        }

        insertExtReqLog(res, custNo);

        callbackService.webHookMonnify(JSON.parseObject(res), custNo);

        return AjaxResult.success();
    }

    @GetMapping("/webhook/paystack")
    @Log(title = "Callback回调地址", businessType = BusinessType.CALLBACK)
    public AjaxResult callbackPaystack(HttpServletRequest request) {
        Enumeration names = request.getParameterNames();
        while(names.hasMoreElements()){
            String name = (String) names.nextElement();
            String value = request.getParameter(name);
            log.info(name+"---"+value);
        }
        return AjaxResult.success();
    }

    private String getCustNoByAccountReference(String res) {
        String accountReference = JSON.parseObject(res).getJSONObject("product").getString("reference");
        QueryWrapper<ExtMonnifyReservedAccounts> monnifyReservedAccountsQueryWrapper = new QueryWrapper<>();
        monnifyReservedAccountsQueryWrapper.eq("account_reference", accountReference).eq("state", UserConstants.BUSINESS_NORMAL).select("cust_no", "account_reference").last("limit 1");
        ExtMonnifyReservedAccounts monnifyReservedAccounts = monnifyReservedAccountsService.getOne(monnifyReservedAccountsQueryWrapper);
        return monnifyReservedAccounts.getCustNo();
    }

    private void insertExtReqLog(String res, String custNo) {
        ExtReqLog extReqLog = new ExtReqLog();
        extReqLog.setReqUrl("/webhook/monnify");
        extReqLog.setReqParam(res);
        extReqLog.setCustNo(custNo);
        extReqLog.setApiName("webhook-monnify");
        extReqLog.setReqTime(DateUtils.dateTimeNow());
        extReqLogService.insertExtReqLog(extReqLog);
    }
//
//    // 需要的地方添加 ----指定，{maxAttempts=4包含第一次}，重试3次，每次补偿(延迟5秒)，每次倍数为1（不变）
//    @Retryable(value = Exception.class,recover = "test",maxAttempts = 4, backoff = @Backoff(delay = 5000, multiplier = 2))
//    public void test(int a){
//        log.info("正常逻辑-----");
//        int c = a/2;
//        log.info("end-----");
//    }
//
//    /**
//     * 悲观锁
//     * 方法的返回值必须与@Retryable方法一致
//     * 方法的第一个参数，必须是Throwable类型的，建议是与@Retryable配置的异常一致，其他的参数，需要哪个参数，写进去就可以了（@Recover方法中有的）
//     * 该回调方法与重试方法写在同一个实现类里面
//     * 由于是基于AOP实现，所以不支持类里自调用方法
//     * 如果重试失败需要给@Recover注解的方法做后续处理，那这个重试的方法不能有返回值，只能是void
//     * 方法内不能使用try catch，只能往外抛异常
//     * ##@Recover注解来开启重试失败后调用的方法(注意,需跟重处理方法在同一个类中)，此注解注释的方法参数一定要是@Retryable抛出的异常，否则无法识别，可以在该方法中进行日志处理。
//     * @param loanOffsetChangeRecord
//     */
//    @Recover
//    public void test(Exception e,LoanOffsetChangeRecord loanOffsetChangeRecord){
//        log.info(e.getMessage());
//        log.info("重试几次都失败，最后回调");
//    }

}
